/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package action.administration;

import static com.opensymphony.xwork2.Action.SUCCESS;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.validator.annotations.DoubleRangeFieldValidator;
import com.opensymphony.xwork2.validator.annotations.FieldExpressionValidator;
import database.KPDAO;
import database.ProductDAO;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
import model.Product;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.interceptor.validation.SkipValidation;

/**
 *
 * @author Thai Ha Cong
 */
@Namespace("/Administration/Bidding")
public class KPAction extends ActionSupport {

    private Product product;
    private double revenue;
    private double revenuePerClick;
    private double conversionRate;
    private double budget;
    private double spentBudget;
    private double bmin;
    private Map<String, String> revMap;
    private Integer idProduct;
    //sample data
    private double output;

    public KPAction() {
    }

    public Product getProduct() {
        return product;
    }

    public void setProduct(Product product) {
        this.product = product;
    }

    public double getRevenuePerClick() {
        return revenuePerClick;
    }

    public void setRevenuePerClick(double revenuePerClick) {
        this.revenuePerClick = revenuePerClick;
    }

    public double getConversionRate() {
        return conversionRate;
    }

    @DoubleRangeFieldValidator(message = "Conversion Rate should be in (0, 1].", minExclusive = "0", maxInclusive = "1")
    public void setConversionRate(double conversionRate) {
        this.conversionRate = conversionRate;
    }

    public Map<String, String> getRevMap() {
        return revMap;
    }

    public void setRevMap(Map<String, String> revMap) {
        this.revMap = revMap;
    }

    public Integer getIdProduct() {
        return idProduct;
    }

    public void setIdProduct(Integer idProduct) {
        this.idProduct = idProduct;
    }

    public double getRevenue() {
        return revenue;
    }

    @DoubleRangeFieldValidator(message = "Revenue should be in (0, 1000].", minExclusive = "0", maxInclusive = "1000")
    public void setRevenue(double revenue) {
        this.revenue = revenue;
    }

    public double getBmin() {
        return bmin;
    }

    @DoubleRangeFieldValidator(message = "Minimum Bid should > 0.", minExclusive = "0")
    @FieldExpressionValidator(expression = "bmin < revenue", message = "Minimum Bid shoule be less than Revenue.")
    public void setBmin(double bmin) {
        this.bmin = bmin;
    }

    public double getBudget() {
        return budget;
    }

    @DoubleRangeFieldValidator(message = "Budget should be in (0, 100000].", minExclusive = "0", maxInclusive = "100000")
    public void setBudget(double budget) {
        this.budget = budget;
    }

    public double getSpentBudget() {
        return spentBudget;
    }

    @DoubleRangeFieldValidator(message = "Spent Budget should >= 0.", minInclusive = "0")
    @FieldExpressionValidator(expression = "spentBudget < budget", message = "Spent Budget must be less than Budget to continue.")
    public void setSpentBudget(double spentBudget) {
        this.spentBudget = spentBudget;
    }

    public double getOutput() {
        return output;
    }

    public void setOutput(double output) {
        this.output = output;
    }

    @Override
    public String execute() throws Exception {
        return SUCCESS;
    }

    @Override
    public void validate() {
    }

    @Action(value = "kpAlgorithm", results = {
        @Result(name = "success", location = "/administration/selectProduct.jsp")
    })
    @SkipValidation
    public String kpAlgorithm() {
        revMap = getRevMapFromDB();

        return SUCCESS;
    }

    @Action(value = "kpUpload", results = {
        @Result(name = "success", location = "/administration/kpResult.jsp")
    })
    @SkipValidation
    public String upload() {
        if (idProduct != 0) {
            KPDAO kpdao = new KPDAO();
            ProductDAO productDAO = new ProductDAO();

            revenue = kpdao.getKPrevFromProductId(idProduct).getKpRevenue();
            product = productDAO.getProductFromProductId(idProduct);
        } else {
            revenue = 0;
        }

        return SUCCESS;
    }

    @Action(value = "kpResult", results = {
        @Result(name = "success", location = "/administration/kpResult.jsp"),
        @Result(name = "input", location = "/administration/kpResult.jsp")
    })
    public String process() throws IOException {
        revenuePerClick = revenue * conversionRate;

        //Revenue Maximization
        output = this.revMax();

        return SUCCESS;
    }

    public double revMax() {
        double result;

        double z;
        double c;
        double psi;
        double e = Math.E;    //nepe
        double recommendedBid;

        //c = 1/ln(Ue/L), if 0<=z<=c, psi(z) = L
        c = 1 / (Math.log(revenuePerClick * e / bmin));

        //Online KP
        z = spentBudget / budget;
        if (z <= c) {
            //psi = L
            psi = 1;
        } else {
            psi = Math.pow(revenuePerClick / bmin, z) * Math.pow(e, z - 1);
        }

        recommendedBid = revenuePerClick / psi;
        //end Online KP

        result = recommendedBid;
        //revenuePerClick = Math.round(revenuePerClick*100.0)/100.0;
        
        return result;
    }

    private Map<String, String> getRevMapFromDB() {
        Map<String, String> result = new LinkedHashMap<String, String>();

        result.put("0", "");

        KPDAO kpdao = new KPDAO();
        for (KPrev kpr : kpdao.getAllKPrev()) {
            result.put("" + kpr.getIdProduct(), kpr.getIdProduct() + " - " + kpr.getName());
        }

        return result;
    }
}